import React, { useEffect } from "react";

type design1type = {
  menling: string;
};

type design2type = {
  suo: string;
  huawen: string;
  create: () => string;
};

export default (): JSX.Element => {
  const design1 = () => {
    // 单例模式（一个类只有唯一的实例）
    // 作用：模块通信，保护自己的属性和方法，系统中某个类的对象只能存在一个（men）
    // 注意：this的使用，清除不用的闭包
    // 解释小王去小李家要按门铃进行通信
    let xiaoli = (function (args) {
      var men: design1type;
      class xiaolijia implements design1type {
        menling!: string;
        constructor(message: string) {
          this.menling = message;
        }
      }
      var info = {
        sendMessage: function (message: string) {
          if (!men) {
            men = new xiaolijia(message);
          }
          return men;
        },
      };
      return info;
    })();
    let xiaowang = {
      callxiaoli: function (msg: string) {
        var _xl: design1type | null = xiaoli.sendMessage(msg);
        alert(_xl.menling);
        _xl = null; // 清空闭包等待垃圾回收
      },
    };
    xiaowang.callxiaoli("你好");
  };

  const design2 = () => {
    // 构造函数模式(可以和单例进行结合)
    // 解释：定制不同类型的门
    // 作用：用于创建特定类型的对象，声明使用对象和传参，可以在构造函数中自定义属性
    // 注意：区分和单例的区别配合单例实现初始化，构造函数建议大写开头，注意new成本（继承）
    function Zaomen(this: any, insuo?: string, inhuawen?: string) {
      var _suo = "普通";
      var _huawen = "普通";
      this.suo = insuo ?? _suo;
      this.huawen = inhuawen ?? _huawen;
      this.create = function () {
        return this.suo + this.huawen;
      };
    }
    // @ts-ignore
    var xiaozhang: design2type = new Zaomen("高级的");
    console.log(xiaozhang.create());
  };

  const design3 = () => {
    // 建造者模式（例如ajax success回调就相当于建造者）
    // 类似盖房子一个客户 ---> 一个指挥者 ---> 一个建造者
    // 作用：分步骤建造一个复杂对象（各个部分会经常变化），解耦封装过程和具体的组件，无需关心如何组装组件
    // 注意：要有稳定的算法进行支持，过程直接暴露（要避免客户和建造者直接接触）
    function Fangzi(this: any) {
      this.woshi = "";
      this.keting = "";
      this.chufang = "";
    }

    function Baogongtou(this: any) {
      this.gaifangzi = function (gongren: any) {
        gongren.jian_woshi();
        gongren.jian_keting();
        gongren.jian_chufang();
      };
    }

    function Gongren(this: any) {
      this.jian_woshi = function () {
        console.log("卧室我建好了");
      };
      this.jian_keting = function () {
        console.log("客厅我建好了");
      };
      this.jian_chufang = function () {
        console.log("厨房我建好了");
      };
      this.jiaogong = function () {
        var _fangzi = new Fangzi.prototype.constructor();
        return _fangzi;
      };
    }
    var gongren = new Gongren.prototype.constructor();
    var baogongtou = new Baogongtou.prototype.constructor();
    baogongtou.gaifangzi(gongren);
    var myfangzi = gongren.jiaogong(); // 主人要房子但是没有接触到工人盖房子
    console.log(myfangzi);
  };

  const design4 = () => {
    // 工厂模式(子类继承父类并且可以改写其中的方法)
    // 定义一个用于创建对象的接口，这俄格接口由子类决定实例化哪一类（工厂 ---> 厂长 ---> 对应生产线）
    // 作用：对象的构建十分复杂，依赖具体环境创建不同的实例，处理大量具有相同对象的小对象
    // 注意：不能滥用有时候仅仅是给代码增加复杂度
    var gongchang: { [key: string]: any } = {};
    gongchang.chanyifu = function (args: any) {
      this.gongren = 50;
      console.log(this.gongren);
    };
    gongchang.chanxie = function (args: any) {
      this.gongren = 30;
      console.log(this.gongren);
    };
    gongchang.yunshu = function (args: any) {
      console.log("运输");
    };
    gongchang.changzhang = function (args: any) {
      return new gongchang[args]();
    };
    var me = gongchang.changzhang("chanyifu");
    console.log(me);
  };

  const design5 = () => {
    // 外观模式(个人理解就是封装然后用时进行调用)
    // 解释：例如mvc
    // 作用：系统分层减少代码之间的依赖，利于维护（通过接口的形式进行对应的关系）
    // 注意：外观模式会产生一定的性能问题，因为每次都要监测功能的可用性
    var fuhao: { [key: string]: any } = {};
    fuhao.huofang = function () {
      return "馒头";
    };
    fuhao.chuliliangshi = function () {
      return "面粉";
    };
    fuhao.mantou = function () {
      this.chuliliangshi();
      this.huofang();
    };
    fuhao.men = function () {
      return this.mantou();
    };
  };

  const design6 = () => {
    // 代理模式（帮代理对象做事情以及一些逻辑处理比如中介卖房）
    // 为其他对象提供代理以控制这个对象的访问（一些难以复制的东西）
    // 作用：远程代理（将不同空间的对象进行局部代理），虚拟代理（骨架屏），安全代理（控制真实对象的访问权限），智能指引（代理垃圾回收机制）
    // 注意：不能滥用，有时候仅仅是给代码增加复杂度
    function maijia(this: any, args: any) {
      this.name = "小明";
    }

    function zhongjie(args: any) {}
    zhongjie.prototype.maifang = function () {
      new fangdong.prototype.constructor(
        new maijia.prototype.constructor()
      ).maifang1("20W");
    };
    function fangdong(this: any, maijia: any) {
      this.name = maijia.name;
      this.maifang1 = function (momey: string) {
        console.log("收到：", momey);
      };
    }
    new zhongjie.prototype.constructor().maifang();
  };

  const design7 = () => {
    // 观察者模式又叫发布订阅模式
    // 一种一对多的关系,多个观察者监听同一个主题对象（发布者）
    // 作用：支持广播通信，自动通知所有已经订阅的对象
    // 注意：监听要在触发之前
    var eventList: { [key: string]: any } | null = {};
    function jianting(name: string, callback: () => void) {
      if (eventList && eventList[name]) {
        eventList[name].push(callback);
      }
      if (eventList && !eventList[name]) {
        eventList[name] = [callback];
      }
    }
    function fabu(name: string, callback: () => void) {
      if (eventList && eventList[name]) {
        eventList[name].forEach((item: () => void) => item());
      } else {
        return;
      }
    }
    function qingchu() {
      eventList = null;
    }
  };

  const design8 = () => {
    // 策略模式
    // 封装各种算法进行调用
    // 作用：所有这些算法都是做相同的事但是实现不同，减少各种算法和使用算法之间的耦合
    // 注意：不仅是算法还有各种规则
    var val = {
      isEmpty: function (str: string) {
        return false;
      },
      isTel: function (str: string) {
        return false;
      },
    };
    var name = "3423424";
    if (!val.isEmpty(name) && !val.isEmpty(name)) {
      console.log(7654);
    }
    // 将上述的代码改成antd design的form表单验证规则
  };

  const design9 = () => {
    // 命令模式
    // 将函数的调用、请求和操作封装成单一对象
    // 作用：将函数的封装、请求、调用结合为一体，调用具体函数解耦命令和接收命令
    // 注意：不需要接口一致，直接调用函数即可，以免浪费
    var lian: { [key: string]: any } = {};
    lian.paobing = function (num: number) {
      console.log(num);
    };
    lian.bubing = function (num: number) {
      console.log(num);
    };
    lian.lianzhang = function (minling: any) {
      lian[minling.type](minling.num);
    };
    lian.lianzhang({
      type: "paobing",
      num: 10,
    });
    lian.lianzhang({
      type: "bubing",
      num: 10,
    });
  };

  const design10 = () => {
    // 迭代器模式（便利的过程）
    // 提供一个方法顺序访问对象中的各个元素，但是又不需要暴露方法中的内部表示
    // 作用：为遍历不同的集合结构提供一个统一的接口，不暴露内部结构且不影响外部访问
    // 注意：至少有两个方法hasnext和next来遍历链条，遍历迭代器修改item会导致问题
    var arr: any[] = [1, 3, 3, 5, 6];
    var diedai = (function (): {
      hasNext: () => boolean;
      next: () => any;
      reset: () => void;
    } {
      var length = arr.length;
      var index = 0;
      return {
        hasNext: function () {
          return index < length;
        },
        next: function () {
          var data = arr[index];
          index = index + 1;
          return data;
        },
        reset: function () {
          index = 0;
        },
      };
    })();
    while (diedai.hasNext()) {
      console.log(diedai.next());
    }
  };

  const design11 = () => {
    // 职责链模式（dom冒泡，每个节点都有机会处理这个点击事件）
    // 使多个对象都有机会处理请求，通过对象连成链条并通过链条传递数据
    // 作用：node操作controller中有很多负责操作逻辑的时候拆分中间件，解耦发送者和接受者
    // 注意：js每次“.”都是有代价的应该在必要时候才用
    function laoban(this: any, xiangmujingli: string) {
      if (xiangmujingli) {
        this.xiangmujingli = xiangmujingli;
      }
    }
    laoban.prototype.write = function (php: string) {
      this.xiangmujingli.write(php);
    };
    function xiangmujingli(this: any, code: string) {
      if (code) {
        this.code = code;
      }
    }
    xiangmujingli.prototype.write = function (php: string) {
      this.code.write(php);
    };
    function code(this: any, php: string) {}
    code.prototype.write = function (php: string) {
      console.log("完成了", php);
    };
    var begin = new laoban.prototype.constructor(
      new xiangmujingli.prototype.constructor(new code.prototype.constructor())
    );
    begin.write("php");
  };

  const design12 = () => {
    // 适配器模式（类似usb转接头）
    // 将一个类的接口转化为需要的类型让不能兼容的类转化成能兼容的
    // 作用：使用一个已经存在的对象，但是其方法或接口口不符合要求，结合多个不相关的功能并暴露
    // 注意：区别于代理，代理不改变接口，适配器会改变接口
    function pp(this: any) {
      this.test = function () {
        console.log("新的test");
      };
    }
    pp.prototype.go = function () {
      console.log("新的gogo");
    };
    function shipeiqi() {
      var s = new pp.prototype.constructor();
      var aa = {
        test: function () {
          s.test();
        },
        go: function () {
          s.go();
        },
      };
      return aa;
    }
    var aa = new shipeiqi.prototype.constructor();
    aa.go();
    aa.test();
  };

  const design13 = () => {
    // 模板方法(类似原型链继承)
    // 代码复用的技巧可以复用公共的方法比如造人方式一样但是每个人却又不同的特点
    // 作用：一次性实现一个算法不可变的部分并给自雷留出可变的行为，控制子类扩展
    // 注意：不同于策略模式，模板方法使用继承来改变算法，策略模式使用委托来改成整个算法
    function shangdi() {}
    shangdi.prototype.yanjing = function() {
      console.log('眼睛')
    }
    shangdi.prototype.zuiba = function() {
      console.log('嘴巴')
    }
    shangdi.prototype.aihao = function() {
      throw new Error("钩子");
    }
    function xiaoming(this: any) {
      console.log('小明是上帝的子类')
      shangdi.call(this)
    }
    // @ts-ignore
    xiaoming.prototype = new xiaoming.prototype.constructor()
    xiaoming.prototype.aihao = function() {
      console.log('小明爱讲笑话')
    }
  };

  const design14 = () => {
    // 原型模式
    // 指用原型实例指向创建对象的种类，并通过拷贝这些原型创建新的对象（和原先的没有关系）Object.create
    // 作用：使用构造器创建对象（new可以通过Object.create）
    // 注意：注意深浅拷贝的问题
    
  }

  useEffect(() => {
    // design1() // 单例模式
    // design2() // 构造函数模式
    // design3() // 建造者模式
    // design4() // 工厂模式
    // design5() // 外观模式
    // design6() // 代理模式
    // design7() // 观察者模式，发布订阅模式
    // design8() // 策略模式
    // design9() // 命令模式
    // design10() // 迭代器模式
    // design11() // 职责链模式
    // design12() // 适配器模式
    // design13() // 模板方法
    design14(); // 原型模式
  }, []);
  return <div>设计模式</div>;
};
